{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "49085ebdf517e721",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### 经典又兼具备趣味性的Kaggle案例[泰坦尼克号问题](https://www.kaggle.com/c/titanic)\n",
    "大家都熟悉的『Jack and Rose』的故事，豪华游艇倒了，大家都惊恐逃生，可是救生艇的数量有限，无法人人都有，副船长发话了『lady and kid first！』，所以是否获救其实并非随机，而是基于一些背景有rank先后的。<br>\n",
    "训练和测试数据是一些乘客的个人信息以及存活状况，要尝试根据它生成合适的模型并预测其他人的存活状况。<br>\n",
    "对，这是一个二分类问题，很多分类算法都可以解决。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5f8c259a883dfcd0",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:25:39.284053Z",
     "start_time": "2025-07-16T07:25:38.562917Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pandas import Series, DataFrame\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.model_selection import learning_curve\n",
    "%matplotlib inline\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "plt.rcParams['axes.unicode_minus'] = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e5cc93801a20a4e9",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:25:42.214858Z",
     "start_time": "2025-07-16T07:25:42.203559Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',\n       'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],\n      dtype='object')"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_train = pd.read_csv('data/Train.csv')\n",
    "data_train.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "388abfd0-ef8b-4cb7-b783-d9e31a77e27c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-16T07:25:45.192839Z",
     "start_time": "2025-07-16T07:25:45.184503Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 891 entries, 0 to 890\n",
      "Data columns (total 12 columns):\n",
      " #   Column       Non-Null Count  Dtype  \n",
      "---  ------       --------------  -----  \n",
      " 0   PassengerId  891 non-null    int64  \n",
      " 1   Survived     891 non-null    int64  \n",
      " 2   Pclass       891 non-null    int64  \n",
      " 3   Name         891 non-null    object \n",
      " 4   Sex          891 non-null    object \n",
      " 5   Age          714 non-null    float64\n",
      " 6   SibSp        891 non-null    int64  \n",
      " 7   Parch        891 non-null    int64  \n",
      " 8   Ticket       891 non-null    object \n",
      " 9   Fare         891 non-null    float64\n",
      " 10  Cabin        204 non-null    object \n",
      " 11  Embarked     889 non-null    object \n",
      "dtypes: float64(2), int64(5), object(5)\n",
      "memory usage: 83.7+ KB\n"
     ]
    }
   ],
   "source": [
    "data_train.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "242df8cc-0b48-4d73-8687-a2a327b885f9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-16T07:25:49.040537Z",
     "start_time": "2025-07-16T07:25:49.019297Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "       PassengerId    Survived      Pclass         Age       SibSp  \\\ncount   891.000000  891.000000  891.000000  714.000000  891.000000   \nmean    446.000000    0.383838    2.308642   29.699118    0.523008   \nstd     257.353842    0.486592    0.836071   14.526497    1.102743   \nmin       1.000000    0.000000    1.000000    0.420000    0.000000   \n25%     223.500000    0.000000    2.000000   20.125000    0.000000   \n50%     446.000000    0.000000    3.000000   28.000000    0.000000   \n75%     668.500000    1.000000    3.000000   38.000000    1.000000   \nmax     891.000000    1.000000    3.000000   80.000000    8.000000   \n\n            Parch        Fare  \ncount  891.000000  891.000000  \nmean     0.381594   32.204208  \nstd      0.806057   49.693429  \nmin      0.000000    0.000000  \n25%      0.000000    7.910400  \n50%      0.000000   14.454200  \n75%      0.000000   31.000000  \nmax      6.000000  512.329200  ",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>PassengerId</th>\n      <th>Survived</th>\n      <th>Pclass</th>\n      <th>Age</th>\n      <th>SibSp</th>\n      <th>Parch</th>\n      <th>Fare</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>count</th>\n      <td>891.000000</td>\n      <td>891.000000</td>\n      <td>891.000000</td>\n      <td>714.000000</td>\n      <td>891.000000</td>\n      <td>891.000000</td>\n      <td>891.000000</td>\n    </tr>\n    <tr>\n      <th>mean</th>\n      <td>446.000000</td>\n      <td>0.383838</td>\n      <td>2.308642</td>\n      <td>29.699118</td>\n      <td>0.523008</td>\n      <td>0.381594</td>\n      <td>32.204208</td>\n    </tr>\n    <tr>\n      <th>std</th>\n      <td>257.353842</td>\n      <td>0.486592</td>\n      <td>0.836071</td>\n      <td>14.526497</td>\n      <td>1.102743</td>\n      <td>0.806057</td>\n      <td>49.693429</td>\n    </tr>\n    <tr>\n      <th>min</th>\n      <td>1.000000</td>\n      <td>0.000000</td>\n      <td>1.000000</td>\n      <td>0.420000</td>\n      <td>0.000000</td>\n      <td>0.000000</td>\n      <td>0.000000</td>\n    </tr>\n    <tr>\n      <th>25%</th>\n      <td>223.500000</td>\n      <td>0.000000</td>\n      <td>2.000000</td>\n      <td>20.125000</td>\n      <td>0.000000</td>\n      <td>0.000000</td>\n      <td>7.910400</td>\n    </tr>\n    <tr>\n      <th>50%</th>\n      <td>446.000000</td>\n      <td>0.000000</td>\n      <td>3.000000</td>\n      <td>28.000000</td>\n      <td>0.000000</td>\n      <td>0.000000</td>\n      <td>14.454200</td>\n    </tr>\n    <tr>\n      <th>75%</th>\n      <td>668.500000</td>\n      <td>1.000000</td>\n      <td>3.000000</td>\n      <td>38.000000</td>\n      <td>1.000000</td>\n      <td>0.000000</td>\n      <td>31.000000</td>\n    </tr>\n    <tr>\n      <th>max</th>\n      <td>891.000000</td>\n      <td>1.000000</td>\n      <td>3.000000</td>\n      <td>80.000000</td>\n      <td>8.000000</td>\n      <td>6.000000</td>\n      <td>512.329200</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_train.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "# y=f(x) 哪些特征是有效的？"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "1d7ccabd5ddc1f78"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ccc3a4e3-43fe-426d-b892-624debfb3e85",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-16T07:25:56.073303Z",
     "start_time": "2025-07-16T07:25:53.865729Z"
    }
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "keyword grid_b is not recognized; valid keywords are ['size', 'width', 'color', 'tickdir', 'pad', 'labelsize', 'labelcolor', 'labelfontfamily', 'zorder', 'gridOn', 'tick1On', 'tick2On', 'label1On', 'label2On', 'length', 'direction', 'left', 'bottom', 'right', 'top', 'labelleft', 'labelbottom', 'labelright', 'labeltop', 'labelrotation', 'grid_agg_filter', 'grid_alpha', 'grid_animated', 'grid_antialiased', 'grid_clip_box', 'grid_clip_on', 'grid_clip_path', 'grid_color', 'grid_dash_capstyle', 'grid_dash_joinstyle', 'grid_dashes', 'grid_data', 'grid_drawstyle', 'grid_figure', 'grid_fillstyle', 'grid_gapcolor', 'grid_gid', 'grid_in_layout', 'grid_label', 'grid_linestyle', 'grid_linewidth', 'grid_marker', 'grid_markeredgecolor', 'grid_markeredgewidth', 'grid_markerfacecolor', 'grid_markerfacecoloralt', 'grid_markersize', 'grid_markevery', 'grid_mouseover', 'grid_path_effects', 'grid_picker', 'grid_pickradius', 'grid_rasterized', 'grid_sketch_params', 'grid_snap', 'grid_solid_capstyle', 'grid_solid_joinstyle', 'grid_transform', 'grid_url', 'grid_visible', 'grid_xdata', 'grid_ydata', 'grid_zorder', 'grid_aa', 'grid_c', 'grid_ds', 'grid_ls', 'grid_lw', 'grid_mec', 'grid_mew', 'grid_mfc', 'grid_mfcalt', 'grid_ms']",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValueError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[5], line 17\u001B[0m\n\u001B[0;32m     15\u001B[0m plt\u001B[38;5;241m.\u001B[39mscatter(data_train\u001B[38;5;241m.\u001B[39mSurvived, data_train\u001B[38;5;241m.\u001B[39mAge)\n\u001B[0;32m     16\u001B[0m plt\u001B[38;5;241m.\u001B[39mylabel(\u001B[38;5;124mu\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m年龄\u001B[39m\u001B[38;5;124m\"\u001B[39m)                         \u001B[38;5;66;03m# sets the y axis lable\u001B[39;00m\n\u001B[1;32m---> 17\u001B[0m plt\u001B[38;5;241m.\u001B[39mgrid(b\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, which\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmajor\u001B[39m\u001B[38;5;124m'\u001B[39m, axis\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124my\u001B[39m\u001B[38;5;124m'\u001B[39m) \u001B[38;5;66;03m# formats the grid line style of our graphs\u001B[39;00m\n\u001B[0;32m     18\u001B[0m plt\u001B[38;5;241m.\u001B[39mtitle(\u001B[38;5;124mu\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m按年龄看获救分布 (1为获救)\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m     21\u001B[0m plt\u001B[38;5;241m.\u001B[39msubplot2grid((\u001B[38;5;241m2\u001B[39m,\u001B[38;5;241m3\u001B[39m),(\u001B[38;5;241m1\u001B[39m,\u001B[38;5;241m0\u001B[39m), colspan\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m2\u001B[39m)\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\pyplot.py:3144\u001B[0m, in \u001B[0;36mgrid\u001B[1;34m(visible, which, axis, **kwargs)\u001B[0m\n\u001B[0;32m   3137\u001B[0m \u001B[38;5;129m@_copy_docstring_and_deprecators\u001B[39m(Axes\u001B[38;5;241m.\u001B[39mgrid)\n\u001B[0;32m   3138\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mgrid\u001B[39m(\n\u001B[0;32m   3139\u001B[0m     visible: \u001B[38;5;28mbool\u001B[39m \u001B[38;5;241m|\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m   3142\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[0;32m   3143\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m-> 3144\u001B[0m     gca()\u001B[38;5;241m.\u001B[39mgrid(visible\u001B[38;5;241m=\u001B[39mvisible, which\u001B[38;5;241m=\u001B[39mwhich, axis\u001B[38;5;241m=\u001B[39maxis, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\axes\\_base.py:3198\u001B[0m, in \u001B[0;36m_AxesBase.grid\u001B[1;34m(self, visible, which, axis, **kwargs)\u001B[0m\n\u001B[0;32m   3196\u001B[0m     \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mxaxis\u001B[38;5;241m.\u001B[39mgrid(visible, which\u001B[38;5;241m=\u001B[39mwhich, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m   3197\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m axis \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m'\u001B[39m\u001B[38;5;124my\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mboth\u001B[39m\u001B[38;5;124m'\u001B[39m]:\n\u001B[1;32m-> 3198\u001B[0m     \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39myaxis\u001B[38;5;241m.\u001B[39mgrid(visible, which\u001B[38;5;241m=\u001B[39mwhich, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\axis.py:1697\u001B[0m, in \u001B[0;36mAxis.grid\u001B[1;34m(self, visible, which, **kwargs)\u001B[0m\n\u001B[0;32m   1694\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m which \u001B[38;5;129;01min\u001B[39;00m [\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmajor\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mboth\u001B[39m\u001B[38;5;124m'\u001B[39m]:\n\u001B[0;32m   1695\u001B[0m     gridkw[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mgridOn\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m (\u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_major_tick_kw[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mgridOn\u001B[39m\u001B[38;5;124m'\u001B[39m]\n\u001B[0;32m   1696\u001B[0m                         \u001B[38;5;28;01mif\u001B[39;00m visible \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;28;01melse\u001B[39;00m visible)\n\u001B[1;32m-> 1697\u001B[0m     \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mset_tick_params(which\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmajor\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mgridkw)\n\u001B[0;32m   1698\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mstale \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mTrue\u001B[39;00m\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\axis.py:958\u001B[0m, in \u001B[0;36mAxis.set_tick_params\u001B[1;34m(self, which, reset, **kwargs)\u001B[0m\n\u001B[0;32m    945\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m    946\u001B[0m \u001B[38;5;124;03mSet appearance parameters for ticks, ticklabels, and gridlines.\u001B[39;00m\n\u001B[0;32m    947\u001B[0m \n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    955\u001B[0m \u001B[38;5;124;03m    gridlines.\u001B[39;00m\n\u001B[0;32m    956\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m    957\u001B[0m _api\u001B[38;5;241m.\u001B[39mcheck_in_list([\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mmajor\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mminor\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mboth\u001B[39m\u001B[38;5;124m'\u001B[39m], which\u001B[38;5;241m=\u001B[39mwhich)\n\u001B[1;32m--> 958\u001B[0m kwtrans \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_translate_tick_params(kwargs)\n\u001B[0;32m    960\u001B[0m \u001B[38;5;66;03m# the kwargs are stored in self._major/minor_tick_kw so that any\u001B[39;00m\n\u001B[0;32m    961\u001B[0m \u001B[38;5;66;03m# future new ticks will automatically get them\u001B[39;00m\n\u001B[0;32m    962\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m reset:\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\matplotlib\\axis.py:1102\u001B[0m, in \u001B[0;36mAxis._translate_tick_params\u001B[1;34m(kw, reverse)\u001B[0m\n\u001B[0;32m   1100\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m key \u001B[38;5;129;01min\u001B[39;00m kw_:\n\u001B[0;32m   1101\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m key \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m allowed_keys:\n\u001B[1;32m-> 1102\u001B[0m         \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[0;32m   1103\u001B[0m             \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mkeyword \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m is not recognized; valid keywords are \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m   1104\u001B[0m             \u001B[38;5;241m%\u001B[39m (key, allowed_keys))\n\u001B[0;32m   1105\u001B[0m kwtrans\u001B[38;5;241m.\u001B[39mupdate(kw_)\n\u001B[0;32m   1106\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m kwtrans\n",
      "\u001B[1;31mValueError\u001B[0m: keyword grid_b is not recognized; valid keywords are ['size', 'width', 'color', 'tickdir', 'pad', 'labelsize', 'labelcolor', 'labelfontfamily', 'zorder', 'gridOn', 'tick1On', 'tick2On', 'label1On', 'label2On', 'length', 'direction', 'left', 'bottom', 'right', 'top', 'labelleft', 'labelbottom', 'labelright', 'labeltop', 'labelrotation', 'grid_agg_filter', 'grid_alpha', 'grid_animated', 'grid_antialiased', 'grid_clip_box', 'grid_clip_on', 'grid_clip_path', 'grid_color', 'grid_dash_capstyle', 'grid_dash_joinstyle', 'grid_dashes', 'grid_data', 'grid_drawstyle', 'grid_figure', 'grid_fillstyle', 'grid_gapcolor', 'grid_gid', 'grid_in_layout', 'grid_label', 'grid_linestyle', 'grid_linewidth', 'grid_marker', 'grid_markeredgecolor', 'grid_markeredgewidth', 'grid_markerfacecolor', 'grid_markerfacecoloralt', 'grid_markersize', 'grid_markevery', 'grid_mouseover', 'grid_path_effects', 'grid_picker', 'grid_pickradius', 'grid_rasterized', 'grid_sketch_params', 'grid_snap', 'grid_solid_capstyle', 'grid_solid_joinstyle', 'grid_transform', 'grid_url', 'grid_visible', 'grid_xdata', 'grid_ydata', 'grid_zorder', 'grid_aa', 'grid_c', 'grid_ds', 'grid_ls', 'grid_lw', 'grid_mec', 'grid_mew', 'grid_mfc', 'grid_mfcalt', 'grid_ms']"
     ]
    },
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 3 Axes>",
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "fig.set(alpha=0.2)  # 设定图表颜色alpha参数\n",
    "\n",
    "plt.subplot2grid((2,3),(0,0))             # 在一张大图里分列几个小图\n",
    "data_train.Survived.value_counts().plot(kind='bar')# plots a bar graph of those who surived vs those who did not. \n",
    "plt.title(u\"获救情况 (1为获救)\") # puts a title on our graph\n",
    "plt.ylabel(u\"人数\")  \n",
    "\n",
    "plt.subplot2grid((2,3),(0,1))\n",
    "data_train.Pclass.value_counts().plot(kind=\"bar\")\n",
    "plt.ylabel(u\"人数\")\n",
    "plt.title(u\"乘客等级分布\")\n",
    "\n",
    "plt.subplot2grid((2,3),(0,2))\n",
    "plt.scatter(data_train.Survived, data_train.Age)\n",
    "plt.ylabel(u\"年龄\")                         # sets the y axis lable\n",
    "plt.grid(b=True, which='major', axis='y') # formats the grid line style of our graphs\n",
    "plt.title(u\"按年龄看获救分布 (1为获救)\")\n",
    "\n",
    "\n",
    "plt.subplot2grid((2,3),(1,0), colspan=2)\n",
    "data_train.Age[data_train.Pclass == 1].plot(kind='kde')   # plots a kernel desnsity estimate of the subset of the 1st class passanges's age\n",
    "data_train.Age[data_train.Pclass == 2].plot(kind='kde')\n",
    "data_train.Age[data_train.Pclass == 3].plot(kind='kde')\n",
    "plt.xlabel(u\"年龄\")# plots an axis lable\n",
    "plt.ylabel(u\"密度\") \n",
    "plt.title(u\"各等级的乘客年龄分布\")\n",
    "plt.legend((u'头等舱', u'2等舱',u'3等舱'),loc='best') # sets our legend for our graph.\n",
    "\n",
    "\n",
    "plt.subplot2grid((2,3),(1,2))\n",
    "data_train.Embarked.value_counts().plot(kind='bar')\n",
    "plt.title(u\"各登船口岸上船人数\")\n",
    "plt.ylabel(u\"人数\")  \n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "55571ea4-06e2-40e8-82f2-7318b669ce01",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-16T07:26:00.546236Z",
     "start_time": "2025-07-16T07:26:00.413986Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 0 Axes>"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "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bdq4F39/fzNr1iyP8+zYscP979dee81jffv27ebTTz91/87+afPmzeaiiy4yzZs3N02aNDGSTKtWrUyLFi3MxRdfbDZs2GAaNmxYZp27d+82xhgzfPhw8/TTT5uGDRuaUaNGmerVq5vvv//e+Pr6mmrVqpXqoTneI/ZPv/zyi7nlllvM4cOHzeLFi82J/u++f//+pmPHjmW2AVZCoAGqgFGjRpnw8HD3H/m5c+ea6tWrm9WrV5s2bdqY6667zrhcrpOe5/PPPzc///yzMcaY+++/34wePdq9/fvvvzfGGFNQUHDC47/99lsTEBBQ7u2Vv/76q8xj3333XSPJ+Pn5GYfDYRwOh7Hb7cZms7nXHQ6H+4/8373wwgvGZrOZO++808THx5vw8HDz6quvumtq1KiRe9+uXbt63F45btWqVaX+aPfv398MHDjQzJo1y1SrVq3UbZ4GDRqY+fPnu9f3799vqlevbp544gnz/vvvm6CgILN9+3Z3+9SpU03dunVNTk6OadWqlVm3bl2pOoqKiowx/731ZYwx+fn5xhhjPvjgA2O3201GRoYpLCw0CQkJpkePHiY3N9cdkK655hozZcoU07BhQ7Nw4ULTrl07M378eDN//nyzaNEis3jxYnPDDTeYzp07m8WLF5vFixebhQsXmrlz55rCwsIyfzfHbzmVpX///qZ9+/ZltgFWwqBgoAoYNmyY/v3vf6thw4aSpDvuuEM9evRQx44dlZeXp8WLF3vcjvi73377zT1odty4cdq4cWOpfSZOnKhNmzZp6dKlaty4cZn7rFy5Ul26dFF+fr5GjRqloqIimWP/0aPJkyfL399fc+bMUc2aNcusY+DAgSouLlZBQYHy8/OVn5+v5557Tpdffrl7PT8/XyUlJdq0aZPHsb169dLo0aN1zz33KCsrS02bNtUzzzwj6ditpLy8PBljlJubq2+++UZPPfWUbDabxo8f7z7HiW6buFwuPf3003rqqadUq1Ytj7bCwkKPW3W1a9fWunXr9N577+mRRx7R/Pnz1aRJE3e7v7+/fH19Vb16dV177bW68847dfDgQXd7WlqaGjVq5DGQWJKGDh2qu+++WyNHjlS1atVUt25d+fr6at++fWrWrJmqVasmHx8fHT16VElJSerQoYMkycfHR+vWrVO9evW0f/9+/fHHH9q/f7969+6tO+64Q/v373dv37dv3wmfEDs+FUBubm6ppaioiKkCcE5gDA1QBdSqVUsdO3aUdOxx6fHjx+uzzz7TTTfdpJUrV6p37956+OGH1blzZ49xJ5LUpk0bHT16VAEBATpy5Ij8/PxKnd/f318vvfSSSkpK9OSTT6p169Ye7T/88INuuukm3X777XrmmWd0zz33aPXq1Ro/frxWrFihCRMmaP78+e4a/27//v06evRomT83OztbhYWFysjIKNVWUFAgm82mmJgYtW7dWq1bt9Z//vMf/fLLL9qyZYs7oPz111/av3+/Fi9erO7duyszM1MFBQWKiooqNY6mLIGBgUpMTFRYWJh69eqluXPnumstKChwj5eRpEOHDikhIUHVq1dXZmamGjZsqJycHLlcLjkcDhUWFsrX11e5ubl6/vnn5XK5lJeXpxo1akiSoqOjdeWVV+q+++5zP2X16quvaubMmXr++ee1evVq+fr66scff1Tr1q31888/u8fnSMfG4AwePFjNmjXzuIa+ffuqefPmHk+Q/d3w4cM9wt1xBw4cUI0aNeRyuSRJwcHBZR7fpk2bk36OQJXn3Q4iAMYYk5mZad5//31z4403Grvdbnr27Gl++OEHY8yxcRv9+vUz/v7+Jjg42HTq1MkMHz7cLFmyxBhjzJEjR4wxx251XHnlleajjz4yxhjTpUsX8/DDDxtjjOnYsaN58sknjcvlMkeOHDGLFi0qdetp3bp1pqSkxBhjTG5uromLi3PfanrvvfdOWPsDDzxgAgMDTUhIiPtJpLKWatWqGUkmODjYhISEmICAAI+nnLZs2WIiIiLMsmXLTGFhocnIyDDGHBvHEhQUZFq0aOG+LbN8+XITHh7uMY5l7dq1Zd4mu//++92fcbVq1TyupXr16mb9+vXGGGMOHz5s6tevb+666y6TmZlprr/+ejN8+HAzevTo03rKae/evWbKlClm+fLlRpKx2+3m7rvvdv+ubrvtNvP666+boqIiExoaan766acyP9eGDRuaxYsXu9dbtWplPvjgg1L73XbbbeZf//pXmefo0qWL+/qNMaZv377mwQcfNMYc+068/PLLZR4HWBG3nAAvyszM1BVXXKHIyEiNHj1atWvX1ldffaXJkyerRo0a7qd0Xn31VW3evFnPP/+8atWqpcTERFWvXl2FhYXavHmzHn/8cTVo0MB9K+fTTz/VsmXLNH36dK1du1Z2u112u12HDh3SihUr1KNHj1KTz7Vs2VKrV6/WyJEj1aJFC+3cuVNDhgxRx44d9cADDygmJkaDBg3SW2+9peXLl+vHH3/U0aNHNX36dOXl5cnpdOrw4cMnXL744gtJ0o8//iin06mjR48qOTlZ0rGnuK677joVFBTokUceUWBgoIYPHy7p2FNNI0eOVG5urt59911J0pw5c9StWzf30zt/l56e7l7uuOMO9/YaNWro3nvv1fjx4923Zo73vEhSaGiotm7dqk8//VRbt27Vt99+q5UrV2rUqFHKy8tTcXGx7rvvPvn4+OjPP/+UMUYlJSUeT0xJx25bHT16VLfccoskacqUKZozZ44++OADBQUF6cYbb9T8+fO1bt06+fv7l+qNOZGyrvW4snrHlixZouXLl+v+++93b9u3b5+7Nwk453g7UQHnu1mzZpnvvvvOlJSUGB8fn3J7A+rWrWuM+e/A04MHD5rIyEhzyy23mIULF5prr73WPPfccyY8PNyEhoaaRo0amXr16pmnnnrKREZGmtDQUBMWFmYef/xxY8yxAcK33Xabady4sfHx8TEhISHmtttuMx999JFxOp3uJ5t++eUXk5CQYK6//np3T4vD4XAPEM7JyTHbt283u3fvNunp6WUuc+fONZLMt99+a9LS0syuXbvcn0FmZqbp3bu3GT9+vPnqq69MRkaGKSkpMbm5uaZatWomJSXFfP755yY8PNysX7/e+Pn5lRqQe7yH5u/69+/v0UOxZcsWI8ls3LjRFBUVGUkmNTXV45hPPvnE1KxZ00yfPt1Ur17dvT0/P99ERkaaWrVqmddff73M3+WaNWvM5Zdfbho0aGD+7//+z13Ps88+a+x2u1m4cKHJzs42wcHBJjY21t1bUpZ/9tC0adPG+Pr6egywdjgcxsfHxz34+++1XnjhhaZ///7ubXl5eSY4ONjMmTPHGEMPDc49jKEBvOzuu+92/9vf31+fffaZunfvXmq/xMREjRkzRtJ/B8BGRERo165dqlatmiQpJiZGN9xwgzp16qSQkBA1aNBAv/32mxITE7Vo0SJdffXVHuf08/PTRRddpAYNGuj2229XQkKC5s2bp3nz5p2w3h49eighIUG//PKLe4Dw6tWrddttt8nhcMhms5V53PHp/2+88UYVFRWpYcOG7un7a9SoodmzZysnJ0cbNmzQlClT3Nd0xRVXqFmzZmrWrJlmzpyp6667Ttddd91pz6YsSZdffrk2bNigq666StnZ2ZKkkJAQScd6yx555BF9++23WrJkiQICAjzmmJkxY4YcDoemTJmiAQMG6N577/Xo7SguLtbLL7/s7mXbu3evu+2VV15RXl6eGjZsqODgYMXHx2vWrFlKSEg4rfrfffddDRgwwGPb7bffXmq/l19+WQcOHNC4cePc2xITE1VcXKyuXbuWee78/PxScxkBVsItJ6AKKevWwd+V9STP8T/8M2bMUFxcnG688UZ98skn7vYPPvhA3bp10zXXXKPHHntMWVlZHscnJCTojTfe0DXXXKPAwED179/f/XTTP5f+/furRo0aatq0qXr16uU+R7du3dwT23Xt2lULFy484S2nlJQU5efne7yLaN68eWratKnCwsI0ePBgHTx4UCEhIRo3bpxeffVVSccm/ouJiVFBQYFq1qxZ6v1Ix/399Qh5eXml2tu2bSvp2ABg6b+BpkaNGrr66qu1detWxcbGavv27apbt66kY++AGjNmjMaMGaPu3bvriiuuUM+ePT3eW2W32zVv3jx98cUXCg8PL/XE0aRJk9SqVSslJiZq3rx5iomJ0eOPP+6egO9U3H///fL19fVY5s+f77FPUlKSxo8fr9GjR6tOnTqSjt3mGzlypIYPH+6+3n9q0qSJ+5YeYEUEGqCKOXjwYKn3FmVkZCgrK6vMx3I3btyorl276rHHHtPLL7+sjz/+WH5+fiopKVFJSYl8fX2VmJioyZMna+bMmYqKitKgQYP066+/nlF9J+qBkY4Fsnr16umuu+7y6KGQyn+L+NVXX63+/fvrxx9/1K5duzR48GCNGzdOTz75pNq1a6e0tDTddNNNWrBggebPn6/169erc+fOHk/9HH/xZVRUlHv57LPPTvhCzJ9++kl+fn7u2XNtNpuGDRumyMhIHT58WP/v//0/devWTfv371d8fLzatGmjAQMGyGaz6cMPP1RGRoY6derkEUiCg4Plcrk0cuRIDR06VJGRke621atXq0uXLho0aJAmT56srVu3Kjw8XC1atNC4cePcPUZ/v56//76NMZoxY4aKioo8ln/22BhjdNttt2no0KEqKirS9OnTdc011yg2NlYvvPCCez9fX19t2rRJ27dv15IlS5Senu4x2zBgOd650wWgLMcn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+vjjjyVJc+bMUYMGDTRnzhx9+eWXmjFjhjIyMjR16lS1bdtWq1at0s8//6wHHnjglOf5AQDA27w+KPif6tevr/r165922/nIx8dHdrtdGRkZGjNmjKKiopSfny+HwyFfX18FBATonXfe0WOPPabs7GyFhISob9++6tWrl+rWraujR49q6tSpmjhxojIyMnTVVVdJOnZb6tJLL5WPD+8uBVAFvRjq7QrOHS86vV1BheEvlkUVFBSoU6dOatOmjRYsWKBp06Zp4cKFaty4sS688EKtX79eAwYM0GWXXaY1a9boX//6l6RjPTcbNmxQSUmJPvvsM7300ktavXq1Fi9erD179ig3N1dbtmxRs2bNvHyFAACcuirXQ4NT4+/vr++++06HDx9WfHy8MjMz1b59e+3du1dOp1M1a9bUwIEDS93au/jii9WrVy8NHTpUnTt31o4dO/Txxx/rX//6lzp27KglS5ZoyZIlevvtt710ZQAAnD56aCxs06ZN6tixo5588kk1b95c+/btkyTNnj1b1113nWbPni2n87/dicnJybrhhhs0bdo0DRs2THXq1NGXX36p119/XbNmzdKjjz6qUaNGKSsrS5dddpm3LgsAgNNGoLGo3NxcjR49Wu+//75uvfVWHTx4UNWqVZPT6dRrr72msWPHqlevXnr44YdVUlIi6VivzjXXXKOvv/5ajRo1kiQ1adJEX331lW6++WaFhobqjz/+UFRU1BnNMgwAgLdwy6kc/8vMvWdb9erVtWzZMknSqlWrlJ2drXr16qlXr1669dZbdcUVV6hZs2a6+uqrNWDAAL3zzjtq2rSpxowZo2+//VZr1qxxvyiySZMmev/99/Xiiy/qzTff1KxZs9S5c2dNnjxZzZs39+ZlAgBwSuihsbB9+/apQ4cO6tevnz766CNdd9118vf312uvvSZJCgwM1IoVK5SamqoxY8a4j5s4caJWrFih3r17S5JmzJihN998U5999pkGDRqkL7/8Uq1bt9a9996r/Px8r1wbAACnw2bOg5nTsrOzFRoaKqfTqZCQEI+2/Px87d69WzExMe7J56zkm2++UVxcnBwOh7Zt26YmTZqUmkH56NGj8vPzk69v2R1yBQUFklTq3Vgul6tC3on1d1b/vAFUATy2XXGq+GPb5f39/iduOVncdddd5/5306ZNy9znZK8vKO8lnwAA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AACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5RFoAACA5Xkt0Bw8eFDffvutMjMzvVUCAAA4R3gl0Hz66ae68MIL9eijj+qCCy7Qp59+KklKSUlRbGyswsPDNWLECBlj3MeU1wYAAM5vlR5oDh8+rCFDhmjt2rX6/vvv9c477+iZZ56Ry+VSfHy82rRpo6SkJKWmpioxMVGSym0DAACo9ECTk5OjN954Q82bN5cktWrVSllZWVq6dKmcTqcmTZqkxo0ba+zYsZoxY4YkldsGAADgW9k/MCoqSn379pUkFRYWasKECbr11luVnJystm3bKigoSJLUsmVLpaamSlK5bWVxuVxyuVzu9ezs7LN1OQAAoArw2qDg5ORk1a5dW8uXL9cbb7yh7OxsxcTEuNttNpvsdruysrLKbStLQkKCQkND3UtUVNRZvx4AAOA9Xgs0LVu21MqVK9WsWTMNHDhQvr6+cjgcHvsEBAQoLy+v3LayjBo1Sk6n072kp6eftesAAADe57VAY7PZdNlllykxMVELFy5URESE/vrrL499cnJy5O/vX25bWRwOh0JCQjwWAABw7qr0QPP1119rxIgR7nVf32PDeC655BJt3LjRvT0tLU0ul0sRERGKjY09YRsAAEClB5pLLrlE77zzjqZPn6709HSNHDlSnTt3Vrdu3eR0OjVz5kxJ0rhx49SpUyfZ7XZ16NDhhG0AAAA244UZ6pYtW6Zhw4YpIyNDXbp00dtvv61atWppwYIF6tOnj4KDg1VcXKzVq1erWbNmklRu28lkZ2crNDRUTqeT208AYHUvhnq7gnPHi05vV1Cu0/n77ZVAU569e/cqKSlJcXFxqlWr1im3lYdAAwDnEAJNxTmHAk2lz0NzMvXr11f9+vVPuw0AAJy/eNs2AACwPAINAACwPAINAACwPAINAACwPAINAACwPAINAACwPAINAACwvAoLNMYYFRcXV9TpAAAATtkZBZpHHnlELpfLY9vXX3+tSy+9tEKKAgAAOB1nFGjeeeedUoGmWbNm2rNnT4UUBQAAcDpO69UHx992bYzRrFmzFBQU5F7/6quvdMUVV1R8hQAAACdxWoHmgw8+kCTZbDZ98skn8vU9driPj48uvPBCzZ49u+IrBAAAOInTCjTffPONpGMB5j//+Q9vrgYAAFXCGY2heeihh+RwOCq6FgAAgDNyWj00x02dOlUul0vp6ekyxni0XXDBBRVSGAAAwKk6o0Dz1ltvacSIESooKPAINDabjbloAABApTujW04vvPCCxo8fr/z8fJWUlLgXwgwAAPCGMwo0ISEhuuGGG+Tn51fR9QAAAJy2Mwo0kydP1oMPPqiUlJSKrgcAAOC0ndEYmqFDh+rgwYNq1aqVwsPDPR7f3rVrV4UVBwAAcCrOKNAkJiZWcBkAAABn7owCTUxMTEXXAQAAcMbOKNBER0fLZrO5H9m22WzuNp50AgAAle2MBgUff0S7pKRER44c0TfffKNrr71WK1eurOj6AAAATuqMemj+LjAwUB06dNCiRYvUoUMHbdmypSLqAgAAOGVn1ENTlgMHDuiPP/6oqNMBAACcsjMeFPzPcTN//PGHnnjiiYqqCwAA4JRVyGPbNptNDRo0UKNGjSqiJgAAgNNyRrecOnbsqI4dOyowMFCZmZkKDAwkzAAAAK85ox6avXv3qkePHtq5c6fq1aunffv2qUmTJlq4cKHq1atX0TUCAACU64x6aB566CFdccUV+uuvv7Rt2zb9+eefuvzyy/XAAw9UdH0AAAAndUY9NOvWrdNPP/0kf39/SVJAQICeffZZtWzZskKLAwAAOBVn1EPTokULffjhhx7bPvzwQzVv3rxCigIAADgdZ9RDM3XqVHXp0kWffPKJYmJitGvXLuXk5Gj58uUVXR8AAMBJnVGgad68uXbs2KHFixcrPT1dAwYMULdu3VStWrWKrg8AAOCkzuiWU2pqqtq3by+73a4RI0bo5Zdf1lVXXaUdO3ZUdH0AAAAndcZPOV1//fXq3LmzJGnjxo3q3r27Bg8eXKHFAQAAnIozuuX0ww8/aO7cuQoNDZUkVatWTUOGDNGll15aocUBAACcijN+yumjjz7y2PbRRx+pWbNmFVIUAADA6TijHpopU6bopptu0ocffqjo6Gjt3r1bWVlZ+vLLLyu6PgAAgJM6o0Bz2WWXaefOnfriiy+UkZGhe++9V926dVNwcHBF1wcAAHBSZxRoJCk4OFh33313RdYCAABwRs5oDA0AAEBVQqABAACWR6ABAACWR6ABAACWR6ABAACWR6ABAACWR6ABAACWR6ABAACWR6ABAACWR6ABAACWd8avPsBZ8mKotys4N7zo9HYFAIBKRA8NAACwPAINAACwPAINAACwPAINAACwPAINAACwPAINAACwPK8EmoULF6pRo0by9fXVVVddpW3btkmSUlJSFBsbq/DwcI0YMULGGPcx5bUBAIDzW6UHmt9++00DBw7UuHHjtHfvXjVs2FCDBg2Sy+VSfHy82rRpo6SkJKWmpioxMVGSym0DAACo9ECzbds2jR07Vnfeeadq166thx9+WElJSVq6dKmcTqcmTZqkxo0ba+zYsZoxY4YkldsGAABQ6TMFd+/e3WN9+/btuvDCC5WcnKy2bdsqKChIktSyZUulpqZKUrltZXG5XHK5XO717Ozsir4MAABQhXh1UHBBQYEmTJigRx55RNnZ2YqJiXG32Ww22e12ZWVlldtWloSEBIWGhrqXqKios34tAADAe7waaJ577jlVr15dDz74oHx9feVwODzaAwIClJeXV25bWUaNGiWn0+le0tPTz9o1AAAA7/PayylXrFihadOmaePGjfLz81NERIRSUlI89snJyZG/v3+5bWVxOBylAhAAADh3eaWHZteuXerbt6+mTp2qSy+9VJIUGxurjRs3uvdJS0uTy+VSREREuW0AAACVHmiOHj2q7t27q2fPnurRo4dyc3OVm5ur9u3by+l0aubMmZKkcePGqVOnTrLb7erQocMJ2wAAACr9ltOyZcu0bds2bdu2Te+++657++7duzV9+nT16dNHI0aMUHFxsVavXn2sSF/fE7YBAABUeqDp2bPnCWf5jY6O1s6dO5WUlKS4uDjVqlXL47gTtQEAgPOb1wYFn0j9+vVVv379024DAADnL15OCQAALI9AAwAALI9AAwAALI9AAwAALK/KDQoGUMW8GOrtCs4dLzq9XQFwzqKHBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAAWB6BBgAA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v/5arVq1kiRlZGSoefPmOnz4sBcrPT9YZqZgVL5rr71Wv//+u6QT/1evzWbjjwcqzQUXXKA1a9botttuk3Qs4IwfP1433nij7rnnHq1atcq7BeK8cvHFF2v37t3atm2bmjZtKj8/P33zzTdq2bKle58vv/xS9evX92KV5w9uOeGENm/erKuuukpvvPGGSkpKylwIM6hMkyZN0oMPPqjp06d7bL/xxhu1YcMGrVmzxkuV4XwUERGht99+Wx07dtTs2bMlySPMPP3003ryySf1xhtveKnC8wu3nFCugwcPqnfv3nr33XcVHR3t7XIA7dq1S9u2bVO3bt1KteXn52vZsmXq0aOHFyrD+er4E00NGjTw2P7NN9/okksuUd26db1U2fmFQAMAACyPW04AAMDyCDQAAMDyCDQAAMDyCDQALCUtLU02m83bZQCoYgg0AADA8gg0AADA8gg0ACpdYmKirrzySvXo0UOhoaHq2rWr/vjjD0nS999/r6uvvlrVq1dXu3bt9PPPP5/SOdeuXavWrVsrKChIsbGxSklJcbctX75cTZs2VVBQkNq1a6fffvvN3fbxxx8rOjpa1apV00033cSLBAGLItAA8IrNmzfr6quv1g8//CCHw6HBgwcrOztbXbt21S233KLt27erbdu26tu370nPVVJSottvv1133HGHdu3apbi4OI0YMcLd3q9fP91///3asWOHmjdvrueee06SlJubq4EDB2rcuHFKTU2Vr6+vJkyYcNauGcDZw7ucAHhFgwYN9Mwzz8hms+nFF19UbGysFixYoIiICI0aNUqS9Nxzz+nKK688pfMlJycrNDRUP/74o3JycrRjxw53W2BgoFwul0JDQzVt2jSVlJRIkux2u/z8/ORyuRQZGalFixbxtm7AouihAeAVDRo0cD+tVL9+fRUXF+uPP/7weMVGeHi47rrrrpOey8fHR5MmTVL9+vX16KOPyul0erxnbPbs2Vq1apXq1q2ra665Rlu3bpV0LOh89tlnmj59umrVqqWuXbtq165dFXuhACoFgQaAV+zZs8fdU7Jnzx75+vqqQYMG2r17t3uf3NxcNW/eXPv37y/3XKtWrdLUqVO1bds2JSUl6f7773e3HTlyREeOHNGKFSt06NAhtW/fXvfdd5+kY+8qCw8P1/r16/Xnn38qMjJSw4YNOwtXC+BsI9AA8Ip9+/YpISFBu3fv1ksvvaQePXooPj5eWVlZGjt2rDIyMvTKK6+ouLhYtWvXLvdcubm5ko69JHD9+vUaPny4+9ZRSUmJunXrpo8//liZmZny8fFxB6nMzEzdcMMN+vLLL5Wdne3RBsBaCDQAvKJt27b6/vvv1bp1axUUFOitt95SSEiIvvzySy1evFhNmzbVxo0b9e9///ukE+kdH0h8+eWXa/DgwXrggQe0b98+/fnnnwoODtbHH3+sV199VY0bN9bixYs1depUSdLFF1+siRMn6uGHH1ajRo20fft2jR8/vjIuH0AF423bACpdYmKiEhMTtWrVKm+XAuAcQQ8NAACwPHpoAACA5dFDAwAALI9AAwAALI9AAwAALI9AAwAALI9AAwAALI9AAwAALI9AAwAALI9AAwAALI9AAwAALO//A4M+spg+MmItAAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#看看各乘客等级的获救情况\n",
    "fig = plt.figure()\n",
    "fig.set(alpha=0.2)  # 设定图表颜色alpha参数\n",
    "\n",
    "Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()\n",
    "Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()\n",
    "df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})\n",
    "df.plot(kind='bar', stacked=True)\n",
    "plt.title(u\"各乘客等级的获救情况\")\n",
    "plt.xlabel(u\"pclass\") \n",
    "plt.ylabel(u\"count\") \n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 处理缺失值\n",
    "<font color=red>先从最突出的数据属性开始吧，对，Cabin和Age，有丢失数据实在是对下一步工作影响太大。<font><br>\n",
    "\n",
    "<font color=red>先说Cabin，暂时我们就按照刚才说的，按Cabin有无数据，将这个属性处理成Yes和No两种类型吧。<font><br>\n",
    "\n",
    "<font color=red>再说Age：<font><br>\n",
    "\n",
    "<font color=red>通常遇到缺值的情况，我们会有几种常见的处理方式<font><br>\n",
    "\n",
    "1. <font color=red>如果缺值的样本占总数比例极高，我们可能就直接舍弃了，作为特征加入的话，可能反倒带入noise，影响最后的结果了<font><br>\n",
    "2. <font color=red>如果缺值的样本适中，而该属性非连续值特征属性(比如说类目属性)，那就把NaN作为一个新类别，加到类别特征中<font><br>\n",
    "3. <font color=red>如果缺值的样本适中，而该属性为连续值特征属性，有时候我们会考虑给定一个step(比如这里的age，我们可以考虑每隔2/3岁为一个步长)，然后把它离散化，之后把NaN作为一个type加到属性类目中。<font><br>\n",
    "4. <font color=red>有些情况下，缺失的值个数并不是特别多，那我们也可以试着根据已有的值，拟合一下数据，补充上。<font><br>\n",
    "<font color=red>本例中，后两种处理方式应该都是可行的，我们先试试拟合补全吧(虽然说没有特别多的背景可供我们拟合，这不一定是一个多么好的选择)<font><br>\n",
    "\n",
    "<font color=red>我们这里用scikit-learn中的RandomForest来拟合一下缺失的年龄数据<font><br>"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "745b3557c051ea6d"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "from sklearn.ensemble import RandomForestRegressor\n",
    "\n",
    "def set_missing_ages(df):\n",
    "    # 把已有的数值型特征取出来丢进Random Forest Regressor中\n",
    "    age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]\n",
    "    known_age = age_df[age_df.Age.notnull()].values\n",
    "    unknown_age = age_df[age_df.Age.isnull()].values\n",
    "    y = known_age[:, 0]\n",
    "    X = known_age[:, 1:]\n",
    "    rf_reg = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)\n",
    "    rf_reg.fit(X, y)\n",
    "    predictedAges = rf_reg.predict(unknown_age[:, 1:])\n",
    "    df.loc[(df.Age.isnull()), 'Age'] = predictedAges\n",
    "    return df, rf_reg\n",
    "data_train, rf_reg = set_missing_ages(data_train)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:31:00.864029Z",
     "start_time": "2025-07-16T07:30:58.436242Z"
    }
   },
   "id": "c36ab9719328c2ea",
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "Age\n24.000000    30\n22.000000    27\n18.000000    26\n30.000000    25\n19.000000    25\n             ..\n0.920000      1\n42.574516     1\n41.574877     1\n23.500000     1\n25.977889     1\nName: count, Length: 164, dtype: int64"
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_train['Age'].value_counts()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:31:24.276710Z",
     "start_time": "2025-07-16T07:31:24.270197Z"
    }
   },
   "id": "3d408a8d269350eb",
   "execution_count": 9
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "Cabin\nNo     687\nYes    204\nName: count, dtype: int64"
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def set_Cabin_type(df):\n",
    "    df.loc[(df.Cabin.notnull()), 'Cabin'] = \"Yes\"\n",
    "    df.loc[(df.Cabin.isnull()), 'Cabin'] = \"No\"\n",
    "    return df\n",
    "\n",
    "data_train = set_Cabin_type(data_train)\n",
    "data_train['Cabin'].value_counts()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:32:29.603679Z",
     "start_time": "2025-07-16T07:32:29.595333Z"
    }
   },
   "id": "7fcdf48a3c1a524b",
   "execution_count": 10
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 数据预处理\n",
    "<font color=red>因为逻辑回归建模时，需要输入的特征都是数值型特征，我们通常会先对类目型的特征因子化/one-hot编码。 <font><br>\n",
    "<font color=red>什么叫做因子化/one-hot编码？举个例子：<font><br>\n",
    "\n",
    "<font color=red>以Embarked为例，原本一个属性维度，因为其取值可以是[‘S’,’C’,’Q‘]，而将其平展开为’Embarked_C’,’Embarked_S’, ‘Embarked_Q’三个属性<font><br>\n",
    "\n",
    "* <font color=red>原本Embarked取值为S的，在此处的”Embarked_S”下取值为1，在’Embarked_C’, ‘Embarked_Q’下取值为0<font><br>\n",
    "* <font color=red>原本Embarked取值为C的，在此处的”Embarked_C”下取值为1，在’Embarked_S’, ‘Embarked_Q’下取值为0<font><br>\n",
    "* <font color=red>原本Embarked取值为Q的，在此处的”Embarked_Q”下取值为1，在’Embarked_C’, ‘Embarked_S’下取值为0<font><br>\n",
    "\n",
    "<font color=red>我们使用pandas的”get_dummies”来完成这个工作，并拼接在原来的”data_train”之上，如下所示。<font><br>"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "1c41f8f33f470732"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "   Cabin_No  Cabin_Yes\n0      True      False\n1     False       True\n2      True      False\n3     False       True\n4      True      False",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>Cabin_No</th>\n      <th>Cabin_Yes</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>True</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>True</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>True</td>\n      <td>False</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 因为逻辑回归建模时，需要输入的特征都是数值型特征\n",
    "# 我们先对类目型的特征离散/因子化\n",
    "# 以Cabin为例，原本一个属性维度，因为其取值可以是['yes','no']，而将其平展开为'Cabin_yes','Cabin_no'两个属性\n",
    "# 原本Cabin取值为yes的，在此处的'Cabin_yes'下取值为1，在'Cabin_no'下取值为0\n",
    "# 原本Cabin取值为no的，在此处的'Cabin_yes'下取值为0，在'Cabin_no'下取值为1\n",
    "# 我们使用pandas的get_dummies来完成这个工作，并拼接在原来的data_train之上，如下所示\n",
    "\n",
    "dummy_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin')\n",
    "dummy_Cabin.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:35:00.841746Z",
     "start_time": "2025-07-16T07:35:00.833140Z"
    }
   },
   "id": "86e16d6598ea3976",
   "execution_count": 11
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "dummies_Embarked = pd.get_dummies(data_train['Embarked'], prefix= 'Embarked')\n",
    "\n",
    "dummies_Sex = pd.get_dummies(data_train['Sex'], prefix= 'Sex')\n",
    "\n",
    "dummies_Pclass = pd.get_dummies(data_train['Pclass'], prefix= 'Pclass')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:35:36.263302Z",
     "start_time": "2025-07-16T07:35:36.256967Z"
    }
   },
   "id": "e00aa2c36d6d2d7c",
   "execution_count": 12
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "   Pclass_1  Pclass_2  Pclass_3\n0     False     False      True\n1      True     False     False\n2     False     False      True\n3      True     False     False\n4     False     False      True",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>Pclass_1</th>\n      <th>Pclass_2</th>\n      <th>Pclass_3</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dummies_Pclass.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:35:50.545502Z",
     "start_time": "2025-07-16T07:35:50.538554Z"
    }
   },
   "id": "82c368e3b79fabe5",
   "execution_count": 13
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "   PassengerId  Survived   Age  SibSp  Parch     Fare  Cabin_No  Cabin_Yes  \\\n0            1         0  22.0      1      0   7.2500      True      False   \n1            2         1  38.0      1      0  71.2833     False       True   \n2            3         1  26.0      0      0   7.9250      True      False   \n3            4         1  35.0      1      0  53.1000     False       True   \n4            5         0  35.0      0      0   8.0500      True      False   \n\n   Embarked_C  Embarked_Q  Embarked_S  Sex_female  Sex_male  Pclass_1  \\\n0       False       False        True       False      True     False   \n1        True       False       False        True     False      True   \n2       False       False        True        True     False     False   \n3       False       False        True        True     False      True   \n4       False       False        True       False      True     False   \n\n   Pclass_2  Pclass_3  \n0     False      True  \n1     False     False  \n2     False      True  \n3     False     False  \n4     False      True  ",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>PassengerId</th>\n      <th>Survived</th>\n      <th>Age</th>\n      <th>SibSp</th>\n      <th>Parch</th>\n      <th>Fare</th>\n      <th>Cabin_No</th>\n      <th>Cabin_Yes</th>\n      <th>Embarked_C</th>\n      <th>Embarked_Q</th>\n      <th>Embarked_S</th>\n      <th>Sex_female</th>\n      <th>Sex_male</th>\n      <th>Pclass_1</th>\n      <th>Pclass_2</th>\n      <th>Pclass_3</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>1</td>\n      <td>0</td>\n      <td>22.0</td>\n      <td>1</td>\n      <td>0</td>\n      <td>7.2500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>2</td>\n      <td>1</td>\n      <td>38.0</td>\n      <td>1</td>\n      <td>0</td>\n      <td>71.2833</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3</td>\n      <td>1</td>\n      <td>26.0</td>\n      <td>0</td>\n      <td>0</td>\n      <td>7.9250</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>4</td>\n      <td>1</td>\n      <td>35.0</td>\n      <td>1</td>\n      <td>0</td>\n      <td>53.1000</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>5</td>\n      <td>0</td>\n      <td>35.0</td>\n      <td>0</td>\n      <td>0</td>\n      <td>8.0500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.concat([data_train, dummy_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)\n",
    "df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)\n",
    "df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:36:41.286357Z",
     "start_time": "2025-07-16T07:36:41.272004Z"
    }
   },
   "id": "76ba1591a94d1d0c",
   "execution_count": 14
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "   Age_scaled  Fare_scaled\n0   -0.561377    -0.502445\n1    0.613173     0.786845\n2   -0.267740    -0.488854\n3    0.392945     0.420730\n4    0.392945    -0.486337",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>Age_scaled</th>\n      <th>Fare_scaled</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>-0.561377</td>\n      <td>-0.502445</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>0.613173</td>\n      <td>0.786845</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>-0.267740</td>\n      <td>-0.488854</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>0.392945</td>\n      <td>0.420730</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>0.392945</td>\n      <td>-0.486337</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 标准化，方差过大\n",
    "import sklearn.preprocessing as preprocessing\n",
    "scaler = preprocessing.StandardScaler()\n",
    "#age_scaler = scaler.fit(df['Age'])\n",
    "df['Age_scaled'] = scaler.fit_transform(df['Age'].values.reshape(-1,1))\n",
    "\n",
    "#fare_scaler = preprocessing.StandardScaler()\n",
    "df['Fare_scaled'] = scaler.fit_transform(df['Fare'].values.reshape(-1,1))\n",
    "\n",
    "df[['Age_scaled','Fare_scaled']].head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:46:39.298416Z",
     "start_time": "2025-07-16T07:46:39.288423Z"
    }
   },
   "id": "dd7520de3331d4be",
   "execution_count": 20
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "     PassengerId  Survived        Age  SibSp  Parch     Fare  Cabin_No  \\\n0              1         0  22.000000      1      0   7.2500      True   \n1              2         1  38.000000      1      0  71.2833     False   \n2              3         1  26.000000      0      0   7.9250      True   \n3              4         1  35.000000      1      0  53.1000     False   \n4              5         0  35.000000      0      0   8.0500      True   \n..           ...       ...        ...    ...    ...      ...       ...   \n886          887         0  27.000000      0      0  13.0000      True   \n887          888         1  19.000000      0      0  30.0000     False   \n888          889         0  16.185117      1      2  23.4500      True   \n889          890         1  26.000000      0      0  30.0000     False   \n890          891         0  32.000000      0      0   7.7500      True   \n\n     Cabin_Yes  Embarked_C  Embarked_Q  Embarked_S  Sex_female  Sex_male  \\\n0        False       False       False        True       False      True   \n1         True        True       False       False        True     False   \n2        False       False       False        True        True     False   \n3         True       False       False        True        True     False   \n4        False       False       False        True       False      True   \n..         ...         ...         ...         ...         ...       ...   \n886      False       False       False        True       False      True   \n887       True       False       False        True        True     False   \n888      False       False       False        True        True     False   \n889       True        True       False       False       False      True   \n890      False       False        True       False       False      True   \n\n     Pclass_1  Pclass_2  Pclass_3  Age_scaled  Fare_scaled  \n0       False     False      True   -0.561377    -0.502445  \n1        True     False     False    0.613173     0.786845  \n2       False     False      True   -0.267740    -0.488854  \n3        True     False     False    0.392945     0.420730  \n4       False     False      True    0.392945    -0.486337  \n..        ...       ...       ...         ...          ...  \n886     False      True     False   -0.194330    -0.386671  \n887      True     False     False   -0.781606    -0.044381  \n888     False     False      True   -0.988244    -0.176263  \n889      True     False     False   -0.267740    -0.044381  \n890     False     False      True    0.172717    -0.492378  \n\n[891 rows x 18 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>PassengerId</th>\n      <th>Survived</th>\n      <th>Age</th>\n      <th>SibSp</th>\n      <th>Parch</th>\n      <th>Fare</th>\n      <th>Cabin_No</th>\n      <th>Cabin_Yes</th>\n      <th>Embarked_C</th>\n      <th>Embarked_Q</th>\n      <th>Embarked_S</th>\n      <th>Sex_female</th>\n      <th>Sex_male</th>\n      <th>Pclass_1</th>\n      <th>Pclass_2</th>\n      <th>Pclass_3</th>\n      <th>Age_scaled</th>\n      <th>Fare_scaled</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>1</td>\n      <td>0</td>\n      <td>22.000000</td>\n      <td>1</td>\n      <td>0</td>\n      <td>7.2500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.561377</td>\n      <td>-0.502445</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>2</td>\n      <td>1</td>\n      <td>38.000000</td>\n      <td>1</td>\n      <td>0</td>\n      <td>71.2833</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>0.613173</td>\n      <td>0.786845</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3</td>\n      <td>1</td>\n      <td>26.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>7.9250</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.267740</td>\n      <td>-0.488854</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>4</td>\n      <td>1</td>\n      <td>35.000000</td>\n      <td>1</td>\n      <td>0</td>\n      <td>53.1000</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>0.392945</td>\n      <td>0.420730</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>5</td>\n      <td>0</td>\n      <td>35.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>8.0500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.392945</td>\n      <td>-0.486337</td>\n    </tr>\n    <tr>\n      <th>...</th>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n    </tr>\n    <tr>\n      <th>886</th>\n      <td>887</td>\n      <td>0</td>\n      <td>27.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>13.0000</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>-0.194330</td>\n      <td>-0.386671</td>\n    </tr>\n    <tr>\n      <th>887</th>\n      <td>888</td>\n      <td>1</td>\n      <td>19.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>30.0000</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>-0.781606</td>\n      <td>-0.044381</td>\n    </tr>\n    <tr>\n      <th>888</th>\n      <td>889</td>\n      <td>0</td>\n      <td>16.185117</td>\n      <td>1</td>\n      <td>2</td>\n      <td>23.4500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.988244</td>\n      <td>-0.176263</td>\n    </tr>\n    <tr>\n      <th>889</th>\n      <td>890</td>\n      <td>1</td>\n      <td>26.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>30.0000</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>-0.267740</td>\n      <td>-0.044381</td>\n    </tr>\n    <tr>\n      <th>890</th>\n      <td>891</td>\n      <td>0</td>\n      <td>32.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>7.7500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.172717</td>\n      <td>-0.492378</td>\n    </tr>\n  </tbody>\n</table>\n<p>891 rows × 18 columns</p>\n</div>"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:46:44.200110Z",
     "start_time": "2025-07-16T07:46:44.185070Z"
    }
   },
   "id": "3692cd923d566784",
   "execution_count": 21
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 建立基线模型\n",
    "<font color=red>逻辑回归建模，这里使用scikit-learn中的逻辑回归模型，并使用scikit-learn中的train_test_split模块将数据分割成训练集和测试集，其中测试集大小为30%，并设置随机种子。<font><br>"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "11944e075ee0d4c9"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.8092031425364759\n"
     ]
    }
   ],
   "source": [
    "from sklearn import linear_model\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# 确保 train_df 是正确的 DataFrame\n",
    "train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')\n",
    "\n",
    "# 转换为 numpy 数组\n",
    "train_np = train_df.values\n",
    "y = train_np[:, 0]\n",
    "X = train_np[:, 1:]\n",
    "\n",
    "# 如果 y 是字符串类型，进行编码\n",
    "if isinstance(y[0], str) or y.dtype == object:\n",
    "    le = LabelEncoder()\n",
    "    y = le.fit_transform(y)\n",
    "\n",
    "# 构建并训练模型\n",
    "lr = linear_model.LogisticRegression(C=1.0, penalty='l2', solver='liblinear', max_iter=1000)\n",
    "lr.fit(X, y)\n",
    "\n",
    "# 查看结果\n",
    "print(lr.score(X, y))\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:56:25.479869Z",
     "start_time": "2025-07-16T07:56:25.467801Z"
    }
   },
   "id": "43a20e249cb43e2f",
   "execution_count": 26
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "(891, 14)"
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.shape"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T07:56:59.297171Z",
     "start_time": "2025-07-16T07:56:59.292481Z"
    }
   },
   "id": "b426b762064e7f21",
   "execution_count": 28
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "     PassengerId        Age  SibSp  Parch      Fare  Cabin_No  Cabin_Yes  \\\n0            892  34.500000      0      0    7.8292      True      False   \n1            893  47.000000      1      0    7.0000      True      False   \n2            894  62.000000      0      0    9.6875      True      False   \n3            895  27.000000      0      0    8.6625      True      False   \n4            896  22.000000      1      1   12.2875      True      False   \n..           ...        ...    ...    ...       ...       ...        ...   \n413         1305  30.705727      0      0    8.0500      True      False   \n414         1306  39.000000      0      0  108.9000     False       True   \n415         1307  38.500000      0      0    7.2500      True      False   \n416         1308  30.705727      0      0    8.0500      True      False   \n417         1309  25.755877      1      1   22.3583      True      False   \n\n     Embarked_C  Embarked_Q  Embarked_S  Sex_female  Sex_male  Pclass_1  \\\n0         False        True       False       False      True     False   \n1         False       False        True        True     False     False   \n2         False        True       False       False      True     False   \n3         False       False        True       False      True     False   \n4         False       False        True        True     False     False   \n..          ...         ...         ...         ...       ...       ...   \n413       False       False        True       False      True     False   \n414        True       False       False        True     False      True   \n415       False       False        True       False      True     False   \n416       False       False        True       False      True     False   \n417        True       False       False       False      True     False   \n\n     Pclass_2  Pclass_3  Age_scaled  Fare_scaled  \n0       False      True    0.307526    -0.496637  \n1       False      True    1.256242    -0.511497  \n2        True     False    2.394702    -0.463335  \n3       False      True   -0.261704    -0.481704  \n4       False      True   -0.641190    -0.416740  \n..        ...       ...         ...          ...  \n413     False      True    0.019551    -0.492680  \n414     False     False    0.649064     1.314641  \n415     False      True    0.611115    -0.507017  \n416     False      True    0.019551    -0.492680  \n417     False      True   -0.356130    -0.236263  \n\n[418 rows x 17 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>PassengerId</th>\n      <th>Age</th>\n      <th>SibSp</th>\n      <th>Parch</th>\n      <th>Fare</th>\n      <th>Cabin_No</th>\n      <th>Cabin_Yes</th>\n      <th>Embarked_C</th>\n      <th>Embarked_Q</th>\n      <th>Embarked_S</th>\n      <th>Sex_female</th>\n      <th>Sex_male</th>\n      <th>Pclass_1</th>\n      <th>Pclass_2</th>\n      <th>Pclass_3</th>\n      <th>Age_scaled</th>\n      <th>Fare_scaled</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>892</td>\n      <td>34.500000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>7.8292</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.307526</td>\n      <td>-0.496637</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>893</td>\n      <td>47.000000</td>\n      <td>1</td>\n      <td>0</td>\n      <td>7.0000</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>1.256242</td>\n      <td>-0.511497</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>894</td>\n      <td>62.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>9.6875</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>2.394702</td>\n      <td>-0.463335</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>895</td>\n      <td>27.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>8.6625</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.261704</td>\n      <td>-0.481704</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>896</td>\n      <td>22.000000</td>\n      <td>1</td>\n      <td>1</td>\n      <td>12.2875</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.641190</td>\n      <td>-0.416740</td>\n    </tr>\n    <tr>\n      <th>...</th>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n    </tr>\n    <tr>\n      <th>413</th>\n      <td>1305</td>\n      <td>30.705727</td>\n      <td>0</td>\n      <td>0</td>\n      <td>8.0500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.019551</td>\n      <td>-0.492680</td>\n    </tr>\n    <tr>\n      <th>414</th>\n      <td>1306</td>\n      <td>39.000000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>108.9000</td>\n      <td>False</td>\n      <td>True</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>0.649064</td>\n      <td>1.314641</td>\n    </tr>\n    <tr>\n      <th>415</th>\n      <td>1307</td>\n      <td>38.500000</td>\n      <td>0</td>\n      <td>0</td>\n      <td>7.2500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.611115</td>\n      <td>-0.507017</td>\n    </tr>\n    <tr>\n      <th>416</th>\n      <td>1308</td>\n      <td>30.705727</td>\n      <td>0</td>\n      <td>0</td>\n      <td>8.0500</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>0.019551</td>\n      <td>-0.492680</td>\n    </tr>\n    <tr>\n      <th>417</th>\n      <td>1309</td>\n      <td>25.755877</td>\n      <td>1</td>\n      <td>1</td>\n      <td>22.3583</td>\n      <td>True</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>False</td>\n      <td>False</td>\n      <td>True</td>\n      <td>-0.356130</td>\n      <td>-0.236263</td>\n    </tr>\n  </tbody>\n</table>\n<p>418 rows × 17 columns</p>\n</div>"
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_test = pd.read_csv(\"data/test.csv\")\n",
    "data_test.loc[ (data_test.Fare.isnull()), 'Fare' ] = 0\n",
    "#data_test.head()\n",
    "# 接着我们对test_data做和train_data中一致的特征变换\n",
    "# 首先用同样的RandomForestRegressor模型填上丢失的年龄\n",
    "tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]\n",
    "null_age = tmp_df[tmp_df.Age.isnull()].values\n",
    "# 根据特征属性X预测年龄并补上\n",
    "X = null_age[:, 1:]\n",
    "\n",
    "predictedAges = rf_reg.predict(X)\n",
    "data_test.loc[ (data_test.Age.isnull()), 'Age' ] = predictedAges\n",
    "# #\n",
    "data_test = set_Cabin_type(data_test)\n",
    "dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')\n",
    "dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')\n",
    "dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')\n",
    "dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')\n",
    "\n",
    "\n",
    "df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)\n",
    "df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)\n",
    "df_test['Age_scaled'] = scaler.fit_transform(df_test['Age'].values.reshape(-1,1))\n",
    "df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'].values.reshape(-1,1))\n",
    "df_test"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T08:20:17.194253Z",
     "start_time": "2025-07-16T08:20:17.012437Z"
    }
   },
   "id": "64679e207c93950a",
   "execution_count": 60
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 用测试数据跑一下基线模型分数"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "46e4551deb3b366a"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\anaconda3\\Lib\\site-packages\\sklearn\\base.py:432: UserWarning: X has feature names, but LogisticRegression was fitted without feature names\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')\n",
    "predictions = lr.predict(test)\n",
    "result = pd.DataFrame({'PassengerId':data_test['PassengerId'].values, 'Survived':predictions.astype(np.int32)})\n",
    "result.to_csv(\"logistic_regression_predictions.csv\", index=False)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T08:22:37.410711Z",
     "start_time": "2025-07-16T08:22:37.402174Z"
    }
   },
   "id": "ed3cb80a6d8f64bd",
   "execution_count": 62
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "     PassengerId  Survived\n0            892         0\n1            893         0\n2            894         0\n3            895         0\n4            896         1\n..           ...       ...\n413         1305         0\n414         1306         1\n415         1307         0\n416         1308         0\n417         1309         0\n\n[418 rows x 2 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>PassengerId</th>\n      <th>Survived</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>892</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>893</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>894</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>895</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>896</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>...</th>\n      <td>...</td>\n      <td>...</td>\n    </tr>\n    <tr>\n      <th>413</th>\n      <td>1305</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>414</th>\n      <td>1306</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>415</th>\n      <td>1307</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>416</th>\n      <td>1308</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>417</th>\n      <td>1309</td>\n      <td>0</td>\n    </tr>\n  </tbody>\n</table>\n<p>418 rows × 2 columns</p>\n</div>"
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.read_csv(\"logistic_regression_predictions.csv\")\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T08:23:11.581164Z",
     "start_time": "2025-07-16T08:23:11.572645Z"
    }
   },
   "id": "5c0e2fa8935e05cb",
   "execution_count": 63
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Found input variables with inconsistent numbers of samples: [86, 891]",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValueError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[64], line 45\u001B[0m\n\u001B[0;32m     41\u001B[0m     plt\u001B[38;5;241m.\u001B[39mshow()\n\u001B[0;32m     43\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m plt\n\u001B[1;32m---> 45\u001B[0m plot_learning_curve(lr, \u001B[38;5;124mu\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m学习曲线\u001B[39m\u001B[38;5;124m\"\u001B[39m, X, y)\n",
      "Cell \u001B[1;32mIn[64], line 16\u001B[0m, in \u001B[0;36mplot_learning_curve\u001B[1;34m(estimator, title, X, y, ylim, cv, n_jobs, train_sizes, scoring)\u001B[0m\n\u001B[0;32m      2\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mplot_learning_curve\u001B[39m(estimator, title, X, y, ylim\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, cv\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[0;32m      3\u001B[0m                         n_jobs\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m, train_sizes\u001B[38;5;241m=\u001B[39mnp\u001B[38;5;241m.\u001B[39mlinspace(\u001B[38;5;241m0.1\u001B[39m, \u001B[38;5;241m1.0\u001B[39m, \u001B[38;5;241m5\u001B[39m), scoring\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mr2\u001B[39m\u001B[38;5;124m'\u001B[39m):\n\u001B[0;32m      4\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m      5\u001B[0m \u001B[38;5;124;03m    画出模型的学习曲线\u001B[39;00m\n\u001B[0;32m      6\u001B[0m \u001B[38;5;124;03m    :param estimator: 模型对象\u001B[39;00m\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m     14\u001B[0m \u001B[38;5;124;03m    :param scoring: 评估指标\u001B[39;00m\n\u001B[0;32m     15\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[1;32m---> 16\u001B[0m     train_sizes, train_scores, test_scores \u001B[38;5;241m=\u001B[39m learning_curve(\n\u001B[0;32m     17\u001B[0m         estimator, X, y, cv\u001B[38;5;241m=\u001B[39mcv, n_jobs\u001B[38;5;241m=\u001B[39mn_jobs, train_sizes\u001B[38;5;241m=\u001B[39mtrain_sizes, scoring\u001B[38;5;241m=\u001B[39mscoring\n\u001B[0;32m     18\u001B[0m     )\n\u001B[0;32m     20\u001B[0m     train_scores_mean \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39mmean(train_scores, axis\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m)\n\u001B[0;32m     21\u001B[0m     train_scores_std \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39mstd(train_scores, axis\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m)\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\sklearn\\model_selection\\_validation.py:1548\u001B[0m, in \u001B[0;36mlearning_curve\u001B[1;34m(estimator, X, y, groups, train_sizes, cv, scoring, exploit_incremental_learning, n_jobs, pre_dispatch, verbose, shuffle, random_state, error_score, return_times, fit_params)\u001B[0m\n\u001B[0;32m   1543\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m exploit_incremental_learning \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mhasattr\u001B[39m(estimator, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mpartial_fit\u001B[39m\u001B[38;5;124m\"\u001B[39m):\n\u001B[0;32m   1544\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[0;32m   1545\u001B[0m         \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mAn estimator must support the partial_fit interface \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m   1546\u001B[0m         \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mto exploit incremental learning\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m   1547\u001B[0m     )\n\u001B[1;32m-> 1548\u001B[0m X, y, groups \u001B[38;5;241m=\u001B[39m indexable(X, y, groups)\n\u001B[0;32m   1550\u001B[0m cv \u001B[38;5;241m=\u001B[39m check_cv(cv, y, classifier\u001B[38;5;241m=\u001B[39mis_classifier(estimator))\n\u001B[0;32m   1551\u001B[0m \u001B[38;5;66;03m# Store it as list as we will be iterating over the list multiple times\u001B[39;00m\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\sklearn\\utils\\validation.py:443\u001B[0m, in \u001B[0;36mindexable\u001B[1;34m(*iterables)\u001B[0m\n\u001B[0;32m    424\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Make arrays indexable for cross-validation.\u001B[39;00m\n\u001B[0;32m    425\u001B[0m \n\u001B[0;32m    426\u001B[0m \u001B[38;5;124;03mChecks consistent length, passes through None, and ensures that everything\u001B[39;00m\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    439\u001B[0m \u001B[38;5;124;03m    sparse matrix, or dataframe) or `None`.\u001B[39;00m\n\u001B[0;32m    440\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m    442\u001B[0m result \u001B[38;5;241m=\u001B[39m [_make_indexable(X) \u001B[38;5;28;01mfor\u001B[39;00m X \u001B[38;5;129;01min\u001B[39;00m iterables]\n\u001B[1;32m--> 443\u001B[0m check_consistent_length(\u001B[38;5;241m*\u001B[39mresult)\n\u001B[0;32m    444\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\n",
      "File \u001B[1;32mC:\\ProgramData\\anaconda3\\Lib\\site-packages\\sklearn\\utils\\validation.py:397\u001B[0m, in \u001B[0;36mcheck_consistent_length\u001B[1;34m(*arrays)\u001B[0m\n\u001B[0;32m    395\u001B[0m uniques \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39munique(lengths)\n\u001B[0;32m    396\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mlen\u001B[39m(uniques) \u001B[38;5;241m>\u001B[39m \u001B[38;5;241m1\u001B[39m:\n\u001B[1;32m--> 397\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[0;32m    398\u001B[0m         \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFound input variables with inconsistent numbers of samples: \u001B[39m\u001B[38;5;132;01m%r\u001B[39;00m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m    399\u001B[0m         \u001B[38;5;241m%\u001B[39m [\u001B[38;5;28mint\u001B[39m(l) \u001B[38;5;28;01mfor\u001B[39;00m l \u001B[38;5;129;01min\u001B[39;00m lengths]\n\u001B[0;32m    400\u001B[0m     )\n",
      "\u001B[1;31mValueError\u001B[0m: Found input variables with inconsistent numbers of samples: [86, 891]"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import learning_curve\n",
    "def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,\n",
    "                        n_jobs=1, train_sizes=np.linspace(0.1, 1.0, 5), scoring='r2'):\n",
    "    \"\"\"\n",
    "    画出模型的学习曲线\n",
    "    :param estimator: 模型对象\n",
    "    :param title: 图表标题\n",
    "    :param X: 输入特征\n",
    "    :param y: 目标值\n",
    "    :param ylim: y轴范围\n",
    "    :param cv: 交叉验证策略\n",
    "    :param n_jobs: 并行任务数\n",
    "    :param train_sizes: 训练集比例\n",
    "    :param scoring: 评估指标\n",
    "    \"\"\"\n",
    "    train_sizes, train_scores, test_scores = learning_curve(\n",
    "        estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, scoring=scoring\n",
    "    )\n",
    "\n",
    "    train_scores_mean = np.mean(train_scores, axis=1)\n",
    "    train_scores_std = np.std(train_scores, axis=1)\n",
    "    test_scores_mean = np.mean(test_scores, axis=1)\n",
    "    test_scores_std = np.std(test_scores, axis=1)\n",
    "\n",
    "    plt.figure()\n",
    "    plt.title(title)\n",
    "    if ylim is not None:\n",
    "        plt.ylim(*ylim)\n",
    "    plt.xlabel(\"Training examples\")\n",
    "    plt.ylabel(\"Score (%s)\" % scoring)\n",
    "\n",
    "    plt.grid()\n",
    "    plt.fill_between(train_sizes, train_scores_mean - train_scores_std,\n",
    "                     train_scores_mean + train_scores_std, alpha=0.1, color=\"r\")\n",
    "    plt.fill_between(train_sizes, test_scores_mean - test_scores_std,\n",
    "                     test_scores_mean + test_scores_std, alpha=0.1, color=\"g\")\n",
    "    plt.plot(train_sizes, train_scores_mean, 'o-', color=\"r\", label=\"Training score\")\n",
    "    plt.plot(train_sizes, test_scores_mean, 'o-', color=\"g\", label=\"Cross-validation score\")\n",
    "\n",
    "    plt.legend(loc=\"best\")\n",
    "    plt.show()\n",
    "\n",
    "    return plt\n",
    "\n",
    "plot_learning_curve(lr, u\"学习曲线\", X, y)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T08:28:35.287152Z",
     "start_time": "2025-07-16T08:28:35.101045Z"
    }
   },
   "id": "5968233d30e49607",
   "execution_count": 64
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 模型融合"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "c90c4290f88d4202"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\anaconda3\\Lib\\site-packages\\sklearn\\base.py:432: UserWarning: X has feature names, but BaggingRegressor was fitted without feature names\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import BaggingRegressor\n",
    "\n",
    "train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')\n",
    "train_np = train_df.values\n",
    "\n",
    "# y即Survival结果\n",
    "y = train_np[:, 0]\n",
    "\n",
    "# X即特征属性值\n",
    "X = train_np[:, 1:]\n",
    "\n",
    "if isinstance(y[0], str) or y.dtype == object:\n",
    "    le = LabelEncoder()\n",
    "    y = le.fit_transform(y)\n",
    "\n",
    "# fit到BaggingRegressor之中\n",
    "clf = linear_model.LogisticRegression(C=1.0, penalty='l2', tol=1e-6)\n",
    "bagging_clf = BaggingRegressor(clf, n_estimators=10, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)\n",
    "bagging_clf.fit(X, y)\n",
    "\n",
    "test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')\n",
    "predictions = bagging_clf.predict(test)\n",
    "result = pd.DataFrame({'PassengerId':data_test['PassengerId'].values, 'Survived':predictions.astype(np.int32)})\n",
    "result.to_csv(\"logistic_regression_predictions2.csv\", index=False)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-07-16T08:39:16.775376Z",
     "start_time": "2025-07-16T08:39:16.722394Z"
    }
   },
   "id": "9b5ba80c8e2e90d2",
   "execution_count": 69
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "pd.read_csv('logistic_regression_predictions2.csv')"
   ],
   "metadata": {
    "collapsed": false,
    "is_executing": true
   },
   "id": "3de424dbb13a263b"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "b9cd8c5abb455ebe"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
